package com.ruoyi.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.ListObjectsRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.OSSObjectSummary;
import com.aliyun.oss.model.ObjectListing;
import com.ruoyi.common.core.constant.Constants;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.file.FileUtils;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.system.api.domain.SysFile;
import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.domain.vo.AliYunConfigVO;
import com.ruoyi.system.mapper.SysConfigMapper;
import com.ruoyi.system.mapper.SysFileMapper;
import com.ruoyi.system.utils.FileType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.util.List;

/**
 * @author: cjie
 * @description: 阿里云文件上传
 * @date: 2021/5/8
 */
@Slf4j
@Service
public class FileUploadService {

    private static AliYunConfigVO aliYunConfigVO;
    @Resource
    private SysConfigMapper sysConfigMapper;
    @Resource
    private SysFileMapper sysFileMapper;

    public OSSClient getOssClient() {
        SysConfig source = new SysConfig();
        source.setConfigKey(Constants.CLOUD_STORAGE_CONFIG_KEY);
        SysConfig sysConfig = sysConfigMapper.selectConfig(source);
        aliYunConfigVO = JSON.parseObject(sysConfig.getConfigValue(), AliYunConfigVO.class);
//        OSSClient ossClient = new OSSClient(aliYunConfigVO.getEndpoint(), aliYunConfigVO.getAccessKeyId(), aliYunConfigVO.getAccessKeySecret());
        //本地测试用的外部访问，部署用阿里云内网访问，使用数据库内的配置
        String endpoint = "https://oss-cn-shanghai.aliyuncs.com";
        OSSClient ossClient = new OSSClient(endpoint, aliYunConfigVO.getAccessKeyId(), aliYunConfigVO.getAccessKeySecret());
        return ossClient;
    }


    public R<SysFile> upload(MultipartFile uploadFile) {
        OSSClient ossClient = getOssClient();
        String fileName = uploadFile.getOriginalFilename();
        String filePath = getFilePath(fileName);
        SysFile sysFile = new SysFile();
        sysFile.setName(fileName);
        sysFile.setType(FileType.fileType(fileName));
        sysFile.setSize(FileUtils.formatFileSize(uploadFile.getSize()));
        sysFile.setUrl(aliYunConfigVO.getDomain() + "/" + filePath);
        sysFile.setPathKey(filePath);
        sysFile.setCreateTime(DateUtils.getNowDate());
        // 上传到阿里云
        try {
            ossClient.putObject(aliYunConfigVO.getBucketName(), filePath, new
                    ByteArrayInputStream(uploadFile.getBytes()));
        } catch (Exception e) {
            log.error("上传失败", e);
            //上传失败
            return R.fail("上传失败");
        } finally {
            // 关闭OSSClient。
            ossClient.shutdown();
        }
        if (sysFileMapper.insertSysFile(sysFile) > 0) {
            return R.ok(sysFile);
        }
        return R.fail("上传失败");
    }

    /**
     * @author lastwhisper
     * @desc 生成路径以及文件名 例如：//files/2019/04/28/15564277465972939.jpg
     * @email gaojun56@163.com
     */
    private String getFilePath(String sourceFileName) {
        DateTime dateTime = new DateTime();
        return "files/" + dateTime.toString("yyyy")
                + "/" + dateTime.toString("MM") + "/"
                + dateTime.toString("dd") + "/" + System.currentTimeMillis() +
                RandomUtils.nextInt(100, 9999) + "." +
                StringUtils.substringAfterLast(sourceFileName, ".");
    }

    /**
     * @author lastwhisper
     * @desc 查看文件列表
     * 文档链接 https://help.aliyun.com/document_detail/84841.html?spm=a2c4g.11186623.2.13.3ad5b5ddqxWWRu#concept-84841-zh
     * @email gaojun56@163.com
     */
    public List<OSSObjectSummary> list(String prefix) {
        OSSClient ossClient = getOssClient();
        try {
            // 设置最大个数。
            final int maxKeys = 100;
            // 列举文件。
            ObjectListing objectListing =
                    ossClient.listObjects(new ListObjectsRequest(aliYunConfigVO.getBucketName()).withMaxKeys(maxKeys).withPrefix(prefix));
            List<OSSObjectSummary> sums = objectListing.getObjectSummaries();

            return sums;
        }catch (Exception e){
            log.error("查看oss文件列表异常",e);
        }finally {
            ossClient.shutdown();
        }
        return null;
    }

    /**
     * @author lastwhisper
     * @desc 删除文件  key指包含文件后缀在内的完整路径，例如abc/efg/123.jpg。
     * 文档链接 https://help.aliyun.com/document_detail/84842.html?spm=a2c4g.11186623.6.770.4f9474b4UYlCtr
     * @email gaojun56@163.com
     */
    public AjaxResult delete(String key) {
        OSSClient ossClient = getOssClient();
        try {
            // 根据BucketName,objectName删除文件
            ossClient.deleteObject(aliYunConfigVO.getBucketName(), key);
        } catch (Exception e) {
            log.error("删除oss文件失败");
        } finally {
            ossClient.shutdown();
        }
        return AjaxResult.success();
    }

    /**
     * @author lastwhisper
     * @desc 下载文件  objectName指包含文件后缀在内的完整路径，例如abc/efg/123.jpg。
     * 文档链接 https://help.aliyun.com/document_detail/84823.html?spm=a2c4g.11186623.2.7.37836e84ZIuZaC#concept-84823-zh
     * @email gaojun56@163.com
     */
    public void exportOssFile(OutputStream os, String objectName) {
        // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
        OSSClient ossClient = getOssClient();
        BufferedInputStream in = null;
        BufferedOutputStream out = null;
        try {
            OSSObject ossObject = ossClient.getObject(aliYunConfigVO.getBucketName(), objectName);
            // 读取文件内容。
            in = new BufferedInputStream(ossObject.getObjectContent());
            out = new BufferedOutputStream(os);
            byte[] buffer = new byte[1024];
            int lenght = 0;
            while ((lenght = in.read(buffer)) != -1) {
                out.write(buffer, 0, lenght);
            }
            out.flush();
            out.close();
            in.close();
        } catch (IOException e) {
            log.error("下载oss文件异常", e);
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                log.error("下载oss关闭流异常", e);
            }

            ossClient.shutdown();
        }
    }
}
